
// Compiler implementation of the D programming language
// Copyright (c) 1999-2008 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.

#ifndef DMD_AGGREGATE_H
#define DMD_AGGREGATE_H

#ifdef __DMC__
#pragma once
#endif /* __DMC__ */

#include "../l_service/c_ds/root.h"
#include "dsymbol.h"

struct Identifier;
struct Type;
struct TypeFunction;
struct E_Expression;
struct P_FuncDeclaration;
struct P_CtorDeclaration;
struct P_DtorDeclaration;
struct P_InvariantDeclaration;
struct P_NewDeclaration;
struct P_DeleteDeclaration;
struct P_InterfaceDeclaration;
struct P_ClassInfoDeclaration;
struct P_VarDeclaration;
struct dt_t;


struct P_AggregateDeclaration : P_ScopeDsymbol
{
    Type *type;
    unsigned storage_class;
    enum PROT protection;
    Type *handle;		// 'this' type
    unsigned structsize;	// size of struct
    unsigned alignsize;		// size of struct for alignment purposes
    unsigned structalign;	// struct member alignment in effect
    int hasUnions;		// set if aggregate has overlapping fields
    Array fields;		// P_VarDeclaration fields
    unsigned sizeok;		// set when structsize contains valid data
				// 0: no size
				// 1: size is correct
				// 2: cannot determine size; fwd referenced
    int isdeprecated;		// !=0 if deprecated
    Scope *scope;		// !=NULL means context to use

    int isnested;		// !=0 if is nested
    P_VarDeclaration *vthis;	// 'this' parameter if this aggregate is nested

    // Special member functions
    P_InvariantDeclaration *inv;		// invariant
    P_NewDeclaration *aggNew;		// allocator
    P_DeleteDeclaration *aggDelete;	// deallocator

#if V2
    P_CtorDeclaration *ctor;
    P_CtorDeclaration *defaultCtor;	// default constructor
#endif

    FuncDeclarations dtors;	// Array of destructors
    P_FuncDeclaration *dtor;	// aggregate destructor

#ifdef IN_GCC
    Array methods;              // flat list of all methods for debug information
#endif

    P_AggregateDeclaration(Loc loc, Identifier *id);
    void semantic2(Scope *sc);
    void semantic3(Scope *sc);
    void inlineScan();
    unsigned size(Loc loc);
    static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
    Type *getType();
    void addField(Scope *sc, P_VarDeclaration *v);
    int isDeprecated();		// is aggregate deprecated?
    P_FuncDeclaration *buildDtor(Scope *sc);
    int isNested();

    void emitComment(Scope *sc);
    void toDocBuffer(OutBuffer *buf);

    // For access checking
    virtual PROT getAccess(P_Dsymbol *smember);	// determine access to smember
    int isFriendOf(P_AggregateDeclaration *cd);
    int hasPrivateAccess(P_Dsymbol *smember);	// does smember have private access to members of this class?
    void accessCheck(Loc loc, Scope *sc, P_Dsymbol *smember);

    enum PROT prot();

    // Back end
    Symbol *stag;		// tag symbol for debug data
    Symbol *sinit;
    Symbol *toInitializer();

    P_AggregateDeclaration *isAggregateDeclaration() { return this; }
};

struct P_AnonymousAggregateDeclaration : P_AggregateDeclaration
{
    P_AnonymousAggregateDeclaration()
	: P_AggregateDeclaration(0, NULL)
    {
    }

    P_AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
};

struct P_StructDeclaration : P_AggregateDeclaration
{
    int zeroInit;		// !=0 if initialize with 0 fill
#if V2
    int hasIdentityAssign;	// !=0 if has identity opAssign
    P_FuncDeclaration *cpctor;	// generated copy-constructor, if any

    FuncDeclarations postblits;	// Array of postblit functions
    P_FuncDeclaration *postblit;	// aggregate postblit
#endif

    P_StructDeclaration(Loc loc, Identifier *id);
    P_Dsymbol *syntaxCopy(P_Dsymbol *s);
    void semantic(Scope *sc);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    char *mangle();
    const char *kind();
    int needOpAssign();
    P_FuncDeclaration *buildOpAssign(Scope *sc);
    P_FuncDeclaration *buildPostBlit(Scope *sc);
    P_FuncDeclaration *buildCpCtor(Scope *sc);
    void toDocBuffer(OutBuffer *buf);

    PROT getAccess(P_Dsymbol *smember);	// determine access to smember

    void toObjFile(int multiobj);			// compile to .obj file
    void toDt(dt_t **pdt);
    void toDebug();			// to symbolic debug info

    P_StructDeclaration *isStructDeclaration() { return this; }
};

struct P_UnionDeclaration : P_StructDeclaration
{
    P_UnionDeclaration(Loc loc, Identifier *id);
    P_Dsymbol *syntaxCopy(P_Dsymbol *s);
    const char *kind();

    P_UnionDeclaration *isUnionDeclaration() { return this; }
};

struct BaseClass
{
    Type *type;				// (before semantic processing)
    enum PROT protection;		// protection for the base interface

    P_ClassDeclaration *base;
    int offset;				// 'this' pointer offset
    Array vtbl;				// for interfaces: Array of P_FuncDeclaration's
					// making up the vtbl[]

    int baseInterfaces_dim;
    BaseClass *baseInterfaces;		// if BaseClass is an interface, these
					// are a copy of the P_InterfaceDeclaration::interfaces

    BaseClass();
    BaseClass(Type *type, enum PROT protection);

    int fillVtbl(P_ClassDeclaration *cd, Array *vtbl, int newinstance);
    void copyBaseInterfaces(BaseClasses *);
};

#if V2
#define CLASSINFO_SIZE 	(0x3C+16)	// value of ClassInfo.size
#else
#define CLASSINFO_SIZE 	(0x3C+12)	// value of ClassInfo.size
#endif

struct P_ClassDeclaration : P_AggregateDeclaration
{
    static P_ClassDeclaration *object;
    static P_ClassDeclaration *classinfo;

    P_ClassDeclaration *baseClass;	// NULL only if this is Object
    P_FuncDeclaration *staticCtor;
    P_FuncDeclaration *staticDtor;
    Array vtbl;				// Array of P_FuncDeclaration's making up the vtbl[]
    Array vtblFinal;			// More P_FuncDeclaration's that aren't in vtbl[]

    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
					// rest are Interface's

    int interfaces_dim;
    BaseClass **interfaces;		// interfaces[interfaces_dim] for this class
					// (does not include baseClass)

    BaseClasses *vtblInterfaces;	// array of base interfaces that have
					// their own vtbl[]

    P_ClassInfoDeclaration *vclassinfo;	// the ClassInfo object for this P_ClassDeclaration
    int com;				// !=0 if this is a COM class (meaning
					// it derives from IUnknown)
    int isauto;				// !=0 if this is an auto class
    int isabstract;			// !=0 if abstract class

    int inuse;				// to prevent recursive attempts

    P_ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
    P_Dsymbol *syntaxCopy(P_Dsymbol *s);
    void semantic(Scope *sc);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    int isBaseOf2(P_ClassDeclaration *cd);

    #define OFFSET_RUNTIME 0x76543210
    virtual int isBaseOf(P_ClassDeclaration *cd, int *poffset);

    P_Dsymbol *search(Loc, Identifier *ident, int flags);
#if V2
    int isFuncHidden(P_FuncDeclaration *fd);
#endif
    P_FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
    void interfaceSemantic(Scope *sc);
    int isCOMclass();
    virtual int isCOMinterface();
#if V2
    virtual int isCPPinterface();
#endif
    int isAbstract();
    virtual int vtblOffset();
    const char *kind();
    char *mangle();
    void toDocBuffer(OutBuffer *buf);

    PROT getAccess(P_Dsymbol *smember);	// determine access to smember

    void addLocalClass(ClassDeclarations *);

    // Back end
    void toObjFile(int multiobj);			// compile to .obj file
    void toDebug();
    unsigned baseVtblOffset(BaseClass *bc);
    Symbol *toSymbol();
    Symbol *toVtblSymbol();
    void toDt(dt_t **pdt);
    void toDt2(dt_t **pdt, P_ClassDeclaration *cd);

    Symbol *vtblsym;

    P_ClassDeclaration *isClassDeclaration() { return (P_ClassDeclaration *)this; }
};

struct P_InterfaceDeclaration : P_ClassDeclaration
{
#if V2
    int cpp;				// !=0 if this is a C++ interface
#endif
    P_InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
    P_Dsymbol *syntaxCopy(P_Dsymbol *s);
    void semantic(Scope *sc);
    int isBaseOf(P_ClassDeclaration *cd, int *poffset);
    int isBaseOf(BaseClass *bc, int *poffset);
    const char *kind();
    int vtblOffset();
#if V2
    int isCPPinterface();
#endif
    virtual int isCOMinterface();

    void toObjFile(int multiobj);			// compile to .obj file
    Symbol *toSymbol();

    P_InterfaceDeclaration *isInterfaceDeclaration() { return this; }
};

#endif /* DMD_AGGREGATE_H */
